package com.yeskery.nut.application.netty;

import com.yeskery.nut.application.NutApplication;
import com.yeskery.nut.application.NutServer;
import com.yeskery.nut.application.SecureServerContext;
import com.yeskery.nut.core.Dispatcher;
import com.yeskery.nut.core.ServerContext;
import com.yeskery.nut.core.ServerRequestConfiguration;
import com.yeskery.nut.core.SessionManager;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpContentCompressor;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.HttpServerKeepAliveHandler;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

import javax.net.ssl.SSLEngine;

/**
 * HttpServer初始化对象
 * @author sprout
 * 2022-06-16 11:22
 */
public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {

    /** Nut应用对象 */
    private final NutApplication nutApplication;

    /** WebSocket上下文 */
    private final WebSocketServerContext webSocketServerContext;

    /** 服务上下文 */
    private final ServerContext serverContext;

    /** 请求分发器 */
    private final Dispatcher dispatcher;

    /** Session管理器 */
    private final SessionManager sessionManager;

    /** 服务请求配置对象 */
    private final ServerRequestConfiguration serverRequestConfiguration;

    /** Nut 服务器 */
    private final NutServer nutServer;

    /** SecureServerContext对象 */
    private final SecureServerContext secureServerContext;

    /**
     * 构建HttpServer初始化对象
     * @param nutApplication Nut应用对象
     * @param webSocketServerContext WebSocket上下文
     * @param serverContext 服务上下文
     * @param dispatcher 请求分发器
     * @param sessionManager 会话管理器
     * @param serverRequestConfiguration 服务请求配置对象
     * @param secureServerContext 安全上下文
     * @param nutServer Nut服务器对象
     */
    public HttpServerInitializer(NutApplication nutApplication, WebSocketServerContext webSocketServerContext,
                                 ServerContext serverContext, Dispatcher dispatcher, SessionManager sessionManager,
                                 ServerRequestConfiguration serverRequestConfiguration, SecureServerContext secureServerContext,
                                 NutServer nutServer) {
        this.nutApplication = nutApplication;
        this.webSocketServerContext = webSocketServerContext;
        this.serverContext = serverContext;
        this.dispatcher = dispatcher;
        this.sessionManager = sessionManager;
        this.serverRequestConfiguration = serverRequestConfiguration;
        this.secureServerContext = secureServerContext;
        this.nutServer = nutServer;
    }

    /**
     * 构建HttpServer初始化对象
     * @param nutApplication Nut应用对象
     * @param webSocketServerContext WebSocket上下文
     * @param serverContext 服务上下文
     * @param dispatcher 请求分发器
     * @param sessionManager 会话管理器
     * @param serverRequestConfiguration 服务请求配置对象
     * @param nutServer Nut服务器对象
     */
    public HttpServerInitializer(NutApplication nutApplication, WebSocketServerContext webSocketServerContext,
                                 ServerContext serverContext, Dispatcher dispatcher, SessionManager sessionManager,
                                 ServerRequestConfiguration serverRequestConfiguration, NutServer nutServer) {
        this(nutApplication, webSocketServerContext, serverContext, dispatcher, sessionManager,
                serverRequestConfiguration, null, nutServer);
    }

    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
        if (secureServerContext != null) {
            SSLEngine engine = secureServerContext.getSslContext().createSSLEngine();
            engine.setUseClientMode(false);
            engine.setNeedClientAuth(false);
            pipeline.addFirst("ssl", new SslHandler(engine));
        }
        pipeline.addLast(new HttpServerCodec());
        pipeline.addLast(new HttpServerKeepAliveHandler());
        pipeline.addLast(new ChunkedWriteHandler());
        pipeline.addLast("aggregator", new HttpObjectAggregator(512 * 1024));
        pipeline.addLast(new HttpRequestHandler(nutApplication, webSocketServerContext, serverContext, dispatcher,
                sessionManager, serverRequestConfiguration, nutServer));
        pipeline.addLast("compressor", new HttpContentCompressor());
    }
}
